home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 4
/
Aminet 4 - November 1994.iso
/
aminet
/
dev
/
obero
/
oberon_lib.lha
/
oberon-a
/
source1.lha
/
source
/
ProjectOberon
/
Texts.mod
< prev
Wrap
Text File
|
1994-08-08
|
25KB
|
898 lines
(***************************************************************************
$RCSfile: Texts.mod $
Description: A port of the Project Oberon Texts module
Created by: J. Gutknecht
Ported by: fjc (Frank Copeland)
$Revision: 1.3 $
$Author: fjc $
$Date: 1994/08/08 16:42:00 $
Copyright © 1990-1993, ETH Zuerich
Copyright © 1994, Frank Copeland.
This file is part of the Oberon-A Library.
See Oberon-A.doc for conditions of use and distribution.
Log entries are at the end of the file.
***************************************************************************)
MODULE Texts;
(*
** $C= CaseChk $I= IndexChk $L= LongAdr $N= NilChk
** $P= PortableCode $R= RangeChk $S= StackChk $T= TypeChk
** $V= OvflChk $Z= ZeroVars
*)
IMPORT Files, Fonts, Reals, SYS := SYSTEM;
CONST
(* symbol classes *)
Inval * = 0; (* invalid symbol *)
Name * = 1; (* name s (length len) *)
String * = 2; (* literal string s (length len) *)
Int * = 3; (* integer i (decimal or hexadecimal) *)
Real * = 4; (* real number x *)
LongReal * = 5; (* long real number y *)
Char * = 6; (* special character c *)
TAB = 9X; CR = 0DX; maxD = 9;
LF = 0AX; (* Amiga end-of-line character *)
(* TextBlock = TextBlock off run {run} 0 len {AsciiCode}.
run = fnt [name] col voff len. *)
TextBlockId = 1FFH;
replace * = 0; insert * = 1; delete * = 2; (* op-codes *)
TYPE
Piece = POINTER TO PieceDesc;
PieceDesc = RECORD
f : Files.File;
off : LONGINT;
len : LONGINT;
fnt : Fonts.Font;
col : SHORTINT;
voff : SHORTINT;
prev,
next : Piece
END; (* PieceDesc *)
Text * = POINTER TO TextDesc;
Notifier * = PROCEDURE (T : Text; op : INTEGER; beg, end : LONGINT);
TextDesc * = RECORD
len * : LONGINT;
notify * : Notifier;
trailer : Piece;
org : LONGINT; (* cache *)
pce : Piece;
f : Files.File (* Holds handle for file opened by Open(). *)
END; (* TextDesc *)
Reader * = RECORD (Files.Rider)
eot * : BOOLEAN;
fnt * : Fonts.Font;
col * : SHORTINT;
voff * : SHORTINT;
ref : Piece;
org : LONGINT;
off : LONGINT
END; (* Reader *)
Scanner * = RECORD (Reader)
nextCh * : CHAR;
line * : INTEGER;
class * : INTEGER;
i * : LONGINT;
x * : REAL;
y * : LONGREAL;
c * : CHAR;
len * : SHORTINT;
s * : ARRAY 32 OF CHAR
END; (* Scanner *)
Buffer * = POINTER TO BufDesc;
BufDesc * = RECORD
len * : LONGINT;
header,
last : Piece
END; (* BufDesc *)
Writer * = RECORD (Files.Rider)
buf * : Buffer;
fnt * : Fonts.Font;
col * : SHORTINT;
voff * : SHORTINT
END; (* Writer *)
VAR
W : Writer; WFile : Files.File; DelBuf : Buffer;
(*------------------------------------*)
PROCEDURE ReadName ( VAR R : Files.Rider; VAR name : ARRAY OF CHAR );
VAR i : INTEGER; ch : CHAR;
BEGIN (* ReadName *)
i := 0; Files.Read (R, ch); IF ch = LF THEN ch := CR END;
WHILE ch # 0X DO
name [i] := ch; INC (i); Files.Read (R, ch);
IF ch = LF THEN ch := CR END
END; (* WHILE *)
name [i] := 0X
END ReadName;
(*------------------------------------*)
PROCEDURE WriteName ( VAR W : Files.Rider; VAR name : ARRAY OF CHAR );
VAR i : INTEGER; ch : CHAR;
BEGIN (* WriteName *)
i := 0; ch := name [i];
WHILE ch # 0X DO
Files.Write (W, ch); INC (i); ch := name [i]
END; (* WHILE *)
Files.Write (W, 0X)
END WriteName;
(*------------------------------------*)
PROCEDURE Load *
( T : Text;
f : Files.File;
pos : LONGINT;
VAR len : LONGINT);
VAR
R : Files.Rider;
Q, q, p : Piece;
off : LONGINT;
N, fnt : SHORTINT;
FName : ARRAY 32 OF CHAR;
Dict : ARRAY 32 OF Fonts.Font;
BEGIN (* Load *)
N := 1;
NEW (Q);
Q.f := WFile; Q.off := 0; Q.len := 1; Q.fnt := NIL; Q.col := 0;
Q.voff := 0; p := Q;
Files.Set (R, f, pos); Files.ReadBytes (R, off, SIZE (LONGINT));
LOOP
Files.Read (R, fnt);
IF fnt = 0 THEN EXIT END;
IF fnt = N THEN
ReadName (R, FName);
Dict [N] := Fonts.This (FName);
INC (N)
END; (* IF *)
NEW (q);
q.fnt := Dict [fnt];
Files.Read (R, q.col);
Files.Read (R, q.voff);
Files.ReadBytes (R, q.len, SIZE (LONGINT));
q.f := f; q.off := off;
off := off + q.len;
p.next := q; q.prev := p; p := q
END; (* LOOP *)
p.next := Q; Q.prev := p;
T.trailer := Q; Files.ReadBytes (R, T.len, SIZE (LONGINT));
T.org := -1; T.pce := T.trailer; (* init cache *)
len := off - pos
END Load;
(*------------------------------------*)
(* $D- disable copying of open arrays *)
PROCEDURE Open * ( T : Text; name : ARRAY OF CHAR );
VAR
f : Files.File;
R : Files.Rider;
Q, q : Piece;
id : INTEGER;
len : LONGINT;
BEGIN (* Open *)
T.f := NIL; f := Files.Old (name);
IF f # NIL THEN
Files.Set (R, f, 0); Files.ReadBytes (R, id, SIZE (INTEGER));
IF id = TextBlockId THEN
Load (T, f, 2, len)
ELSE (* Ascii file *)
len := Files.Length (f);
NEW (Q);
Q.fnt := NIL; Q.col := 0; Q.voff := 0; Q.f := WFile;
Q.off := 0; Q.len := 1;
NEW (q);
q.fnt := Fonts.Default; q.col := 1; q.voff := 0; q.f := f;
q.off := 0; q.len := len;
Q.next := q; q.prev := Q; q.next := Q; Q.prev := q;
T.trailer := Q; T.len := len;
T.org := -1; T.pce := T.trailer (* init cache *)
END
ELSE (* create new text *)
NEW (Q);
Q.fnt := NIL; Q.col := 0; Q.voff := 0; Q.f := WFile;
Q.off := 0; Q.len := 1; Q.next := Q; Q.prev := Q;
T.trailer := Q; T.len := 0;
T.org := -1; T.pce := T.trailer (* init cache *)
END;
T.f := f;
END Open;
(*------------------------------------*)
PROCEDURE Close * ( T : Text );
BEGIN (* Close *)
IF T.f # NIL THEN Files.Close (T.f) END
END Close;
(*------------------------------------*)
PROCEDURE OpenBuf * (B : Buffer);
BEGIN (* OpenBuf *)
NEW (B.header); (* null piece *)
B.last := B.header; B.len := 0
END OpenBuf;
(*------------------------------------*)
PROCEDURE FindPiece
( T : Text;
pos : LONGINT;
VAR org : LONGINT;
VAR p : Piece );
VAR n : INTEGER;
BEGIN (* FindPiece *)
IF pos < T.org THEN T.org := -1; T.pce := T.trailer END;
org := T.org; p := T.pce; (* from cache *)
n := 0;
WHILE pos >= org + p.len DO
org := org + p.len; p := p.next; INC (n)
END; (* WHILE *)
IF n > 50 THEN T.org := org; T.pce := p END;
END FindPiece;
(*------------------------------------*)
PROCEDURE SplitPiece ( p : Piece; off : LONGINT; VAR pr : Piece );
VAR q : Piece;
BEGIN (* SplitPiece *)
IF off > 0 THEN
NEW (q);
q.fnt := p.fnt; q.col := p.col; q.voff := p.voff; q.len := p.len - off;
q.f := p.f; q.off := p.off + off;
p.len := off;
q.next := p.next; p.next := q;
q.prev := p; q.next.prev := q;
pr := q
ELSE
pr := p
END; (* ELSE *)
END SplitPiece;
(*------------------------------------*)
PROCEDURE OpenReader * ( VAR R : Reader; T : Text; pos : LONGINT );
VAR p : Piece; org : LONGINT;
BEGIN (* OpenReader *)
FindPiece (T, pos, org, p);
R.ref := p; R.org := org; R.off := pos - org;
Files.Set (R, R.ref.f, R.ref.off + R.off); R.eot := FALSE;
END OpenReader;
(*------------------------------------*)
PROCEDURE Read * ( VAR R : Reader; VAR ch : CHAR );
BEGIN (* Read *)
Files.Read (R, ch); IF ch = LF THEN ch := CR END;
R.fnt := R.ref.fnt; R.col := R.ref.col;
R.voff := R.ref.voff; INC (R.off);
IF R.off = R.ref.len THEN
IF R.ref.f = WFile THEN R.eot := TRUE END;
R.org := R.org + R.off; R.off := 0;
R.ref := R.ref.next;
R.org := R.org + R.off; R.off := 0;
Files.Set (R, R.ref.f, R.ref.off)
END; (* IF *)
END Read;
(*------------------------------------*)
PROCEDURE Pos * ( VAR R : Reader ) : LONGINT;
BEGIN (* Pos *)
RETURN R.org + R.off
END Pos;
(*------------------------------------*)
PROCEDURE Store *
( T : Text;
f : Files.File;
pos : LONGINT;
VAR len : LONGINT );
VAR
p, q : Piece;
R : Reader; W : Files.Rider;
off, rlen : LONGINT; id : INTEGER;
N, n : SHORTINT; ch : CHAR;
Dict : ARRAY 32 OF Fonts.Name;
BEGIN (* Store *)
Files.Set (W, f, pos);
id := TextBlockId; Files.WriteBytes (W, id, SIZE (INTEGER));
Files.WriteBytes (W, off, SIZE (LONGINT)); (* place holder *)
N := 1;
p := T.trailer.next;
WHILE p # T.trailer DO
rlen := p.len; q := p.next;
WHILE
(q # T.trailer)
& (q.fnt = p.fnt) & (q.col = p.col) & (q.voff = p.voff)
DO
rlen := rlen + q.len; q := q.next;
END; (* WHILE *)
Dict [N] := p.fnt.name; n := 1;
WHILE Dict [n] # p.fnt.name DO INC (n) END;
Files.Write (W, n);
IF n = N THEN WriteName (W, p.fnt.name); INC (N) END;
Files.Write (W, p.col); Files.Write (W, p.voff);
Files.WriteBytes (W, rlen, SIZE (LONGINT));
p := q
END; (* WHILE *)
Files.Write (W, 0); Files.WriteBytes (W, T.len, SIZE (LONGINT));
off := Files.Pos (W);
OpenReader (R, T, 0); Read (R, ch);
WHILE ~R.eot DO Files.Write (W, ch); Read (R, ch) END;
Files.Set (W, f, pos + SIZE (INTEGER));
Files.WriteBytes (W, off, SIZE (LONGINT)); (* fixup *)
len := off + T.len - pos
END Store;
(*------------------------------------*)
PROCEDURE Save * ( T : Text; beg, end : LONGINT; B : Buffer );
VAR
p, q, qb, qe : Piece;
org : LONGINT;
BEGIN (* Save *)
IF end > T.len THEN end := T.len END;
FindPiece (T, beg, org, p);
NEW (qb);
qb^ := p^; qb.len := qb.len - (beg - org);
qb.off := qb.off + (beg - org);
qe := qb;
WHILE end > org + p.len DO
org := org + p.len; p := p.next;
NEW (q);
q^ := p^; qe.next := q; q.prev := qe; qe := q
END; (* WHILE *)
qe.next := NIL; qe.len := qe.len - (org + p.len - end);
B.last.next := qb; qb.prev := B.last; B.last := qe;
B.len := B.len + (end - beg)
END Save;
(*------------------------------------*)
PROCEDURE Copy * ( SB, DB : Buffer );
VAR Q, q, p : Piece;
BEGIN (* Copy *)
p := SB.header; Q := DB.last;
WHILE p # SB.last DO
p := p.next;
NEW (q);
q^ := p^; Q.next := q; q.prev := Q; Q := q
END; (* WHILE *)
DB.last := Q; DB.len := DB.len + SB.len
END Copy;
(*------------------------------------*)
PROCEDURE ChangeLooks *
( T : Text;
beg, end : LONGINT;
sel : SET;
fnt : Fonts.Font;
col, voff : SHORTINT );
VAR
pb, pe, p : Piece;
org : LONGINT;
BEGIN (* ChangeLooks *)
IF end > T.len THEN end := T.len END;
FindPiece (T, beg, org, p); SplitPiece (p, beg - org, pb);
FindPiece (T, end, org, p); SplitPiece (p, end - org, pe);
p := pb;
REPEAT
IF 0 IN sel THEN p.fnt := fnt END;
IF 1 IN sel THEN p.col := col END;
IF 2 IN sel THEN p.voff := voff END;
UNTIL p = pe;
T.notify (T, replace, beg, end)
END ChangeLooks;
(*------------------------------------*)
PROCEDURE Insert * ( T : Text; pos : LONGINT; B : Buffer );
VAR
pl, pr, p, qb, qe : Piece;
org, end : LONGINT;
BEGIN (* Insert *)
FindPiece (T, pos, org, p); SplitPiece (p, pos - org, pr);
IF T.org >= org THEN (* adjust cache *)
T.org := org - p.prev.len; T.pce := p.prev
END; (* IF *)
pl := pr.prev;
qb := B.header.next;
IF
(qb # NIL) & (qb.f = pl.f) & (qb.off = pl.off + pl.len)
& (qb.fnt = pl.fnt) & (qb.col = pl.col) & (qb.voff = pl.voff)
THEN
pl.len := pl.len + qb.len; qb := qb.next
END; (* IF *)
IF qb # NIL THEN
qe := B.last;
qb.prev := pl; pl.next := qb; qe.next := pr; pr.prev := qe
END; (* IF *)
T.len := T.len + B.len; end := pos + B.len;
B.last := B.header; B.last.next := NIL; B.len := 0;
T.notify (T, insert, pos, end)
END Insert;
(*------------------------------------*)
PROCEDURE Append * ( T : Text; B : Buffer );
BEGIN (* Append *)
Insert (T, T.len, B)
END Append;
(*------------------------------------*)
PROCEDURE Delete * ( T : Text; beg, end : LONGINT );
VAR
pb, pe, pbr, per : Piece;
orgb, orge : LONGINT;
BEGIN (* Delete *)
IF end > T.len THEN end := T.len END;
FindPiece (T, beg, orgb, pb); SplitPiece (pb, beg - orgb, pbr);
FindPiece (T, end, orge, pe); SplitPiece (pe, end - orge, per);
IF T.org >= orgb THEN (* adjust cache *)
T.org := orgb - pb.prev.len; T.pce := pb.prev
END; (* IF *)
DelBuf.header.next := pbr; DelBuf.last := per.prev;
DelBuf.last.next := NIL; DelBuf.len := end - beg;
per.prev := pbr.prev;
pbr.prev.next := per;
T.len := T.len - DelBuf.len;
T.notify (T, delete, beg, end)
END Delete;
(*------------------------------------*)
PROCEDURE Recall ( VAR B : Buffer ); (* deleted text *)
BEGIN (* Recall *)
B := DelBuf; NEW (DelBuf); OpenBuf (DelBuf)
END Recall;
(*------------------------------------*)
PROCEDURE OpenScanner * ( VAR S : Scanner; T : Text; pos : LONGINT );
BEGIN (* OpenScanner *)
OpenReader (S, T, pos); S.line := 0; Read (S, S.nextCh)
END OpenScanner;
(*------------------------------------*)
PROCEDURE Scan * ( VAR S : Scanner );
CONST
maxD = 32;
(* Limits for exponents *)
MaxNegD = 20; (* LONGREAL : Motorola FFP reals *)
MaxPosD = 18;
MaxNegE = 20; (* REAL : Motorola FFP reals *)
MaxPosE = 18;
VAR
ch, term : CHAR;
neg, negE, hex : BOOLEAN;
i, j, h : SHORTINT;
e : INTEGER; k : LONGINT;
x, f : REAL; y, g : LONGREAL;
d : ARRAY maxD OF CHAR;
(*------------------------------------*)
PROCEDURE ReadScaleFactor ();
BEGIN (* ReadScaleFactor *)
Read (S, ch);
IF ch = "-" THEN
negE := TRUE; Read (S, ch)
ELSE
negE := FALSE; IF ch = "+" THEN Read (S, ch) END;
END;
WHILE (ch >= "0") & (ch <= "9") DO
e := e * 10 + ORD (ch) - 30H; Read (S, ch)
END; (* WHILE *)
END ReadScaleFactor;
BEGIN (* Scan *)
ch := S.nextCh; i := 0;
LOOP
IF (ch = CR) OR (ch = LF) THEN INC (S.line)
ELSIF (ch # " ") & (ch # TAB) THEN EXIT
END;
Read (S, ch)
END; (* LOOP *)
IF (CAP (ch) >= "A") & (CAP (ch) <= "Z") THEN (* name *)
REPEAT
S.s [i] := ch; INC (i); Read (S, ch)
UNTIL
(CAP (ch) > "Z")
OR (CAP (ch) < "A") & (ch > "9")
OR (ch < "0") & (ch # ".")
OR (i = 31);
S.s [i] := 0X; S.len := i; S.class := Name
ELSIF ch = 22X THEN (* literal string *)
Read (S, ch);
WHILE (ch # 22X) & (ch >= " ") & (i # 31) DO
S.s [i] := ch; INC (i); Read (S, ch)
END; (* WHILE *)
S.s [i] := 0X; S.len := i + 1; S.class := String
ELSE
IF ch = "-" THEN neg := TRUE; Read (S, ch) ELSE neg := FALSE END;
IF (ch >= "0") & (ch <= "9") THEN (* number *)
hex := FALSE; j := 0;
LOOP
d [i] := ch; INC (i); Read (S, ch);
IF ch < "0" THEN EXIT END;
IF "9" < ch THEN
IF ("A" <= ch) & (ch <= "F") THEN
hex := TRUE; ch := CHR (ORD (ch) - 7)
ELSIF ("a" <= ch) & (ch <= "f") THEN
hex := TRUE; ch := CHR (ORD (ch) - 27H)
ELSE
EXIT
END; (* ELSE *)
END; (* IF *)
END; (* LOOP *)
IF ch = "H" THEN (* hex number *)
Read (S, ch); S.class := Int;
IF i - j > 8 THEN j := i - 8 END;
k := ORD (d [j]) - 30H; INC (j);
IF (i - j = 7) & (k >= 8) THEN DEC (k, 16) END;
WHILE j < i DO k := k * 10H + (ORD (d [j]) - 30H); INC (j) END;
IF neg THEN S.i := -k ELSE S.i := k END;
ELSIF ch = "." THEN (* read real *)
Read (S, ch); h := i;
WHILE ("0" <= ch) & (ch <= "9") DO
d [i] := ch; INC (i); Read (S, ch)
END;
IF ch = "D" THEN
e := 0; y := 0.0; g := 1.0;
REPEAT y := y * 10.0 + (ORD (d [j]) - 30H); INC (j) UNTIL j = h;
WHILE j < i DO
g := g / 10.0; y := (ORD (d [j]) - 30H) * g + y; INC (j)
END;
ReadScaleFactor;
IF negE THEN
IF e <= MaxNegD THEN y := y / Reals.TenL (e) ELSE y := 0.0 END
ELSIF e > 0 THEN
IF e <= MaxPosD THEN y := y * Reals.TenL (e) ELSE HALT (40) END
END; (* IF *)
IF neg THEN y := -y END;
S.class := LongReal; S.y := y
ELSE
e := 0; x := 0.0; f := 1.0;
REPEAT x := x * 10.0 + (ORD (d [j]) - 30H); INC (j) UNTIL j = h;
WHILE j < i DO
f := f / 10.0; x := (ORD (d [j]) - 30H) * f + x; INC (j)
END;
IF ch = "E" THEN ReadScaleFactor END;
IF negE THEN
IF e <= MaxNegE THEN x := x / Reals.Ten (e) ELSE x := 0.0 END
ELSIF e > 0 THEN
IF e <= MaxPosE THEN x := x * Reals.Ten (e) ELSE HALT (40) END
END; (* IF *)
IF neg THEN x := -x END;
S.class := Real; S.x := x
END; (* ELSE *)
IF hex THEN S.class := Inval END
ELSE (* decimal integer *)
S.class := Int; k := 0;
REPEAT k := k * 10 + (ORD (d [j]) - 30H); INC (j) UNTIL j = i;
IF neg THEN S.i := -k ELSE S.i := k END;
IF hex THEN S.class := Inval ELSE S.class := Int END
END; (* ELSE *)
ELSE
S.class := Char;
IF neg THEN S.c := "-" ELSE S.c := ch; Read (S, ch) END
END; (* ELSE *)
END; (* ELSE *)
S.nextCh := ch
END Scan;
(*------------------------------------*)
PROCEDURE OpenWriter * ( VAR W : Writer );
BEGIN (* OpenWriter *)
NEW (W.buf); OpenBuf (W.buf); W.fnt := Fonts.Default; W.col := 1;
W.voff := 0; Files.Set (W, Files.New (""), 0)
END OpenWriter;
(*------------------------------------*)
PROCEDURE CloseWriter * ( VAR W : Writer );
BEGIN (* CloseWriter *)
Files.Purge (Files.Base (W))
END CloseWriter;
(*------------------------------------*)
PROCEDURE SetFont * ( VAR W : Writer; fnt : Fonts.Font );
BEGIN (* SetFont *)
W.fnt := fnt
END SetFont;
(*------------------------------------*)
PROCEDURE SetColor * ( VAR W : Writer; col : SHORTINT );
BEGIN (* SetColor *)
W.col := col
END SetColor;
(*------------------------------------*)
PROCEDURE SetOffset * ( VAR W : Writer; voff : SHORTINT );
BEGIN (* SetOffset *)
W.voff := voff
END SetOffset;
(*------------------------------------*)
PROCEDURE Write * ( VAR W : Writer; ch : CHAR );
VAR p : Piece;
BEGIN (* Write *)
IF
(W.buf.last.fnt # W.fnt) OR (W.buf.last.col # W.col)
OR (W.buf.last.voff # W.voff)
THEN
NEW (p);
p.f := Files.Base (W); p.off := Files.Pos (W); p.len := 0;
p.fnt := W.fnt; p.col := W.col; p.voff := W.voff;
p.next := NIL; W.buf.last.next := p;
p.prev := W.buf.last; W.buf.last := p
END; (* IF *)
Files.Write (W, ch);
INC (W.buf.last.len); INC (W.buf.len)
END Write;
(*------------------------------------*)
PROCEDURE WriteLn * ( VAR W : Writer );
BEGIN (* WriteLn *)
Write (W, CR)
END WriteLn;
(*------------------------------------*)
(* $D- disable copying of open arrays *)
PROCEDURE WriteString * ( VAR W : Writer; s : ARRAY OF CHAR );
VAR i : LONGINT;
BEGIN (* WriteString *)
i := 0; WHILE s [i] # 0X DO Write (W, s [i]); INC (i) END
END WriteString;
(*------------------------------------*)
PROCEDURE WriteInt * ( VAR W : Writer; x, n : LONGINT );
VAR i : INTEGER; x0 : LONGINT; a : ARRAY 11 OF CHAR;
BEGIN (* WriteInt *)
i := 0;
IF x < 0 THEN
IF x = MIN (LONGINT) THEN
WriteString (W, " -2147483648"); RETURN
ELSE
DEC (n); x0 := -x
END; (* ELSE *)
ELSE
x0 := x
END; (* ELSE *)
REPEAT
a [i] := CHR (x0 MOD 10 + 30H); x0 := x0 DIV 10; INC (i)
UNTIL x0 = 0;
WHILE n > i DO Write (W, " "); DEC (n) END;
IF x < 0 THEN Write (W, "-") END;
REPEAT DEC (i); Write (W, a [i]) UNTIL i = 0;
END WriteInt;
(*------------------------------------*)
PROCEDURE WriteHex * ( VAR W : Writer; x : LONGINT );
VAR i : INTEGER; y : LONGINT; a : ARRAY 10 OF CHAR;
BEGIN (* WriteHex *)
i := 0; Write (W, " ");
REPEAT
y := x MOD 10H;
IF y < 10 THEN a [i] := CHR (y + 30H) ELSE a [i] := CHR (y + 37H) END;
x := x DIV 10H; INC (i)
UNTIL i = 8;
REPEAT DEC (i); Write (W, a [i]) UNTIL i = 0
END WriteHex;
(*------------------------------------*)
PROCEDURE WriteReal * ( VAR W : Writer; x : REAL; n : INTEGER );
VAR e : INTEGER; x0 : REAL; d : ARRAY maxD OF CHAR;
BEGIN (* WriteReal *)
(*
* This implementation uses Motorola FFP format reals instead of IEEE
* single-precision reals. The Project Oberon code has been modified to
* remove the special-case handling of unnormal and NaN values and assume
* 7-bit exponents instead of 8-bit.
*)
e := Reals.Expo (x);
IF n <= 9 THEN n := 3 ELSE DEC (n, 6) END;
REPEAT Write (W, " "); DEC (n) UNTIL n <= 8;
(* there are 2 < n <= 8 digits to be written *)
IF x < 0.0 THEN Write (W, "-"); x := -x ELSE Write (W, " ") END;
e := (e - 64) * 77 DIV 256;
IF e >= 0 THEN x := x / Reals.Ten (e) ELSE x := Reals.Ten (-e) * x END;
IF x >= 10.0 THEN x := 0.1 * x; INC (e) END;
x0 := Reals.Ten (n - 1); x := x0 * x + 0.5;
IF x >= 10.0 * x0 THEN x := x * 0.1; INC (e) END;
Reals.Convert (x, n, d);
DEC (n); Write (W, d [n]); Write (W, ".");
REPEAT DEC (n); Write (W, d [n]) UNTIL n = 0;
Write (W, "E");
IF e < 0 THEN Write (W, "-"); e := -e ELSE Write (W, "+") END;
Write (W, CHR (e DIV 10 + 30H)); Write (W, CHR (e MOD 10 + 30H))
END WriteReal;
(*------------------------------------*)
PROCEDURE WriteRealFix * ( VAR W : Writer; x : REAL; n, k : INTEGER );
VAR e, i : INTEGER; sign : CHAR; x0 : REAL; d : ARRAY maxD OF CHAR;
(*------------------------------------*)
PROCEDURE seq ( ch : CHAR; n : LONGINT );
BEGIN (* seq *)
WHILE n > 0 DO Write (W, ch); DEC (n) END
END seq;
(*------------------------------------*)
PROCEDURE dig (n : INTEGER);
BEGIN (* dig *)
WHILE n > 0 DO
DEC (i); Write (W, d [i]); DEC (n)
END;
END dig;
BEGIN (* WriteRealFix *)
(*
* This implementation uses Motorola FFP format reals instead of IEEE
* single-precision reals. The Project Oberon code has been modified to
* remove the special-case handling of unnormal and NaN values and assume
* 7-bit exponents instead of 8-bit.
*)
IF k < 0 THEN k := 0 END;
e := (Reals.Expo (x) - 64) * 77 DIV 256;
IF x < 0.0 THEN sign := "-"; x := -x ELSE sign := " " END;
IF e >= 0 THEN (* x >= 1.0, 77/256 = log 2 *) x := x / Reals.Ten (e)
ELSE (* x < 1.0 *) x := Reals.Ten (-e) * x END;
IF x >= 10.0 THEN x := 0.1 * x; INC (e) END;
(* 1 <= x < 10 *)
IF k + e >= maxD - 1 THEN k := maxD - 1 - e
ELSIF k + e < 0 THEN k := -e; x := 0.0
END;
x0 := Reals.Ten (k + e); x := x0 * x + 0.5;
IF x >= 10.0 * x0 THEN INC (e) END;
(* e = no. of digits before decimal point *)
INC (e); i := k + e; Reals.Convert (x, i, d);
IF e > 0 THEN
seq (" ", n - e - k - 2); Write (W, sign); dig (e); Write (W, ".");
dig (k)
ELSE
seq (" ", n - k - 3); Write (W, sign); Write (W, "0"); Write (W, ".");
seq ("0", -e); dig (k + e)
END; (* ELSE *)
END WriteRealFix;
(*------------------------------------*)
PROCEDURE WriteRealHex * ( VAR W : Writer; x : REAL );
VAR i : INTEGER; d : ARRAY 8 OF CHAR;
BEGIN (* WriteRealHex *)
Reals.ConvertH (x, d); i := 0;
REPEAT Write (W, d [i]); INC (i) UNTIL i = 8
END WriteRealHex;
(*------------------------------------*)
PROCEDURE WriteLongReal * ( VAR W : Writer; x : LONGREAL; n : INTEGER );
BEGIN (* WriteLongReal *)
(*
* In this implementation, LONGREAL and REAL types are the same, so this
* procedure is implemented as a call to WriteReal ().
*)
WriteReal (W, SHORT (x), n)
END WriteLongReal;
(*------------------------------------*)
PROCEDURE WriteLongRealHex * ( VAR W : Writer; x : LONGREAL );
BEGIN (* WriteLongRealHex *)
(*
* In this implementation, LONGREAL and REAL types are the same, so this
* procedure is implemented as a call to WriteRealHex ().
*)
WriteRealHex (W, SHORT (x))
END WriteLongRealHex;
(*------------------------------------*)
PROCEDURE WriteDate * ( VAR W : Writer; t, d : LONGINT );
(*------------------------------------*)
PROCEDURE WritePair (ch : CHAR; x : LONGINT);
BEGIN (* WritePair *)
Write (W, ch);
Write (W, CHR (x DIV 10 + 30H)); Write (W, CHR (x MOD 10 + 30H))
END WritePair;
BEGIN (* WriteDate *)
WritePair (" ", d MOD 32); WritePair (".", d DIV 32 MOD 16);
WritePair (".", d DIV 512 MOD 128);
WritePair (" ", t DIV 4096 MOD 32); WritePair (":", t DIV 64 MOD 64);
WritePair (":", t MOD 64)
END WriteDate;
(*------------------------------------*)
PROCEDURE * Cleanup ();
BEGIN (* Cleanup *)
CloseWriter (W);
END Cleanup;
BEGIN (* Texts *)
NEW (DelBuf); OpenBuf (DelBuf);
OpenWriter (W); Write (W, 0X);
WFile := Files.Base (W);
SYS.SETCLEANUP (Cleanup)
END Texts.
(***************************************************************************
$Log: Texts.mod $
Revision 1.3 1994/08/08 16:42:00 fjc
Release 1.4
Revision 1.2 1994/05/12 20:45:18 fjc
- Prepared for release
# Revision 1.1 1994/01/15 21:39:12 fjc
# Start of revision control
#
***************************************************************************)